#ifndef SALA_H_
#define SALA_H_

#include "../Game/Juego.h"
#include "../Common/Mutex.h"
#include "../Common/Thread.h"
#include "Cliente.h"
#include "../Common/Jsonizable.h"
#include "Estado.h"
#include "../Common/ConditionVariable.h"
#include "JugadorEnviar.h"
#include "JugadorRecibir.h"
#include "ColaProtegida.h"
#include "VectorProtegido.h"
#include "ArchivoUsuarios.h"

class Sala : public Thread {
	unsigned nivel;
	Juego* juego;
	VectorProtegido<Json::Value*> vectorDeEnvios;
	ColaProtegida<Json::Value*> colaDeRecepciones;
	std::vector<JugadorEnviar*> jugadoresDeEnvio;
	std::vector<JugadorRecibir*> jugadoresDeRecepcion;
	unsigned cantJugadoresConectados;
	unsigned maximoJugadores;
	Estado estado;
	bool estaCorriendo;
	Mutex mutex;
	ConditionVariable conditionVariable;
	std::vector<Cliente*> clientes;
	unsigned cantEnviosRealizados;
	ArchivoUsuarios& archivoUsuarios;
	
	//Va avisadole a los clientes, la cantidad de clientes
	//que se van conectado hasta completar la sala
	void esperarCompletarse();
	
	//Espera las confirmaciones de los jugadores para empezar a jugar.
	void esperarConfirmaciones();
	
	//Evalua los movimientos de los usuarios, hasta que haya un ganador 
	//o pierdan todos.
	void jugar();
	
	//Envia datos a los jugadores.
	void enviar();
	
	//Obtiene un movimiento de la cola de recepciones.
	void obtenerMovimiento(Movimiento& mov, unsigned& idJugador);
	
	//Obtiene el tablero que haya en ese momento.
	void obtenerTableros();
	
	//Obtiene los puntajes de los jugadores.
	void obtenerPuntajes(unsigned& idJugador);
	
	//Le indica a los jugadores que le envien un movimiento.
	void pedirMovimiento();
	
	//Evalua el final del juego, si hubo un ganador, si perdieron todos, 
	//o si se desconectaron y quedo 1 solo, evalua si tiene el 80% del
	//puntaje maximo a alcanzar, en ese caso es el jugador que gano.
	void finDelJuego(unsigned& idJugador);
	
	//Borra todos los elementos de la cola de recepciones
	void limpiarCola();
	
	//Compara el puntaje de un jugador con el maximo.
	//Devuelve True si gano, False si no.
	bool hayGanador(unsigned& idJugador);
	
	//Envia las imagenes personalizadas del agujero o fondo.
	void enviarDatosDeInicio();

public:
	
	//
	Sala(unsigned maximoJugadores, unsigned nivel, ArchivoUsuarios& archUsuarios);
	
	//
	bool agregarJugador(Cliente* cliente);
	
	//
	Estado obtenerEstado();
	
	//
	void setEstado(Estado estado);
	
	//
	void startMethod();
	
	//
	void matar();
	
	//
	Json::Value getJson();
	
	//
	unsigned getNivel() const;
	
	//
	~Sala();
};

#endif /* SALA_H_ */
